package com.andaily.tomcatroot.web.filter;

import com.andaily.tomcatroot.web.WebUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Properties;
import java.util.logging.Logger;

/**
 * @author Shengzhao Li
 */
public class DispatchFilter implements Filter {

    //The key in session, Judge the client is first visit or not
    private static final String IS_CLIENT_FIRST_VISIT = "is_Client_First_Visit";

    //logger
    private static final Logger LOGGER = Logger.getLogger("DispatchFilter");

    private Properties properties;
    //end by '/'
    private String host;

    //mobile support fields
    private boolean mobileSupport;
    private String mobileIndexUri;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //initial properties
        this.properties = new Properties();
        try {
            final String propertiesName = filterConfig.getInitParameter("propertiesName");
            properties.load(this.getClass().getResourceAsStream(propertiesName));
            LOGGER.info("Initial load [" + propertiesName + "]");
        } catch (IOException e) {
            throw new ServletException("Load [tomcat_root.properties] failed", e);
        }
        //load and check host
        this.host = properties.getProperty("host", "andaily.com/");
        if (!this.host.endsWith("/")) {
            this.host = this.host + "/";
        }
        //load and check mobile setting
        this.mobileSupport = Boolean.valueOf(properties.getProperty("mobile.support", "false"));
        if (this.mobileSupport) {
            this.mobileIndexUri = properties.getProperty("mobile.index.uri");
            if (this.mobileIndexUri == null) {
                throw new ServletException("Property [mobile.index.uri] value is required, but it is null, please check [tomcat_root.properties].");
            }
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
            HttpServletRequest servletRequest = (HttpServletRequest) request;
            HttpServletResponse servletResponse = (HttpServletResponse) response;
            //handle domain redirect
            if (handleDomainNames(servletRequest, servletResponse)) {
                return;
            }
            //Mobile support checking
            if (handleMobileClient(servletRequest, servletResponse)) {
                return;
            }
        }
        chain.doFilter(request, response);
    }

    private boolean handleMobileClient(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException {
        //check the client is the first visit or not
        if (isClientFirstVisit(servletRequest)
                && this.mobileSupport
                && WebUtils.isMobileBrowser(servletRequest)) {
            servletResponse.sendRedirect(this.host + this.mobileIndexUri);
            return true;
        }
        return false;
    }


    /**
     * If the client is the first time visit, return true, otherwise false.
     * Just set a value in session , key is {@link #IS_CLIENT_FIRST_VISIT}.
     * if the value is null, it is first visit.
     *
     * @param request HttpServletRequest
     * @return true is first time, otherwise false
     */
    private boolean isClientFirstVisit(HttpServletRequest request) {
        final HttpSession session = request.getSession();
        final Object isFirstVisit = session.getAttribute(IS_CLIENT_FIRST_VISIT);
        if (isFirstVisit == null) {
            // do not care the value
            session.setAttribute(IS_CLIENT_FIRST_VISIT, "no");
            return true;
        }
        return false;
    }

    private boolean handleDomainNames(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws IOException {
        final String requestHost = servletRequest.getHeader("host");
        if (requestHost == null) {
            return false;
        }

        final String application = properties.getProperty(requestHost);
        if (application != null && application.trim().length() > 0) {
            servletResponse.sendRedirect(this.host + application + servletRequest.getRequestURI());
            return true;
        }
        return false;
    }

    @Override
    public void destroy() {
        //nothing
    }
}